package cn.richard.demo.drools.core;

import java.time.LocalDateTime;
import java.util.Properties;

import javax.annotation.PostConstruct;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.env.Environment;

import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.PropertyKeyConst;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.AbstractListener;
import com.alibaba.nacos.api.exception.NacosException;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public abstract class AbsNacosConfigPropertiesListener {

	@Value("${spring.cloud.nacos.config.server-addr}")
	private String serverAddr;

	@Value("${spring.profiles.active}")
	protected String active;

	@Autowired
	protected Environment env;

	public final String DEFAULT_NAMESPACE = "public";
	public final String DEFAULT_GROUP = "DEFAULT_GROUP";

	private String namespace;
	private String group;
	private String dataId;

	private ConfigService configService;
	public final long timeoutMs = 5000;

	@PostConstruct
	private void init() {
		log.info(">> Nacos配置文件坐标初始化与监听");
		initGav();
		getConfigService();
		addListener();
		log.info("<< Nacos配置文件坐标初始化与监听");
	}

	private void initGav() {
		namespace = getNamespace();
		group = getGroup();
		dataId = getDataId();
		log.info("目标配置文件的坐标：{}", getGav());
	}
	public String getGav() {
		return String.format("[dataId:%s, group:%s, namespace:%s]", dataId, group, namespace);
	}

	private void getConfigService() {
		try {
			//TODO：注意，如果加入 PropertyKeyConst.NAMESPACE 配置，该 configService 的  publishConfig相关操作失效...
			configService = NacosFactory.createConfigService(serverAddr);
		} catch (NacosException e) {
			log.error("获取 Nacos ConfigService 异常", e);
			throw new RuntimeException("获取 Nacos ConfigService 异常", e);
		}
	}

	private void addListener() {
		try {
			String content = configService.getConfig(dataId, group, timeoutMs);
			if(null == content) {
				log.error("Nacos上未找到目标配置文件：{}", getGav());
				throw new RuntimeException("Nacos上未找到目标配置文件：" + getGav());
			}
			log.info("配置文件初始内容读取: {}", content);
			configService.addListener(dataId, group, new AbstractListener() {
				@Override
				public void receiveConfigInfo(String configInfo) {
					log.info("监听到配置修改，本次修改后的内容: {}", configInfo);
					onContentChanged(configInfo);// 自实现逻辑，集群节点测试方式：VM arguments add -DServer.port=8001
				}
			});
			log.info("注册配置监听OK: {}", getGav());
		} catch (NacosException e) {
			log.error("Nacos配置文件监听异常", e);
			throw new RuntimeException("Nacos配置文件监听异常", e);
		}
	}

	/**
	 * 使用 ConfigService API 方式直接覆盖修改目标配置文件，从而产生文件修改事件，触发监听动作，广播各节点
	 * @param newContent
	 * @return
	 */
	public boolean publishConfig(String newContent) {
		log.info(">> publishConfig，目标文件：{}，内容：{}", getGav(), newContent);
		try {
			return configService.publishConfig(dataId, group, newContent);
		} catch (NacosException e) {
			log.error("publishConfig 异常", e);
			throw new RuntimeException("publishConfig 异常", e);
		} finally {
			log.info("<< publishConfig");
		}
	}

	protected abstract String getDataId();

	protected abstract String getGroup();

	protected abstract String getNamespace();

	protected abstract void onContentChanged(String newContent);

	//测试
	public static void main(String[] args) throws Exception {
		String serverAddr = "localhost:8848";
		String dataId = "drools-reload-flag-local";
		String group = "DEFAULT_GROUP";

		Properties properties = new Properties();
		properties.put(PropertyKeyConst.SERVER_ADDR, serverAddr);
		//如果加入 PropertyKeyConst.NAMESPACE 配置，该 configService 的  publishConfig相关操作失效...
		ConfigService configService = NacosFactory.createConfigService(properties);
		
		// 读取配置
		String content = configService.getConfig(dataId, group, 5000);
		System.out.println(content);
//
//		// 添加监听器
//		configService.addListener(dataId, group, new Listener() {
//			@Override
//			public void receiveConfigInfo(String configInfo) {
//				log.info("recieve new content: {}" + configInfo);
//			}
//
//			@Override
//			public Executor getExecutor() {
//				return null;
//			}
//		});

		// 推送更新
		boolean isPublishOk = configService.publishConfig(dataId, group, LocalDateTime.now().toString());
		System.out.println(isPublishOk);

		// 移除配置
//		boolean isRemoveOk = configService.removeConfig(dataId, group);
//		System.out.println(isRemoveOk);

//		Thread.sleep(300000);
	}
}
